//
//  ApplicationController.m
//  WSPluginSwitcher
//
//  @author	Jens Krause [www.websector.de]
//	@date		01/01/09
//  @see		http://www.websector.de/blog/
//
//  Licensed under the MIT License http://www.opensource.org/licenses/mit-license.php
//

#import "ApplicationController.h"
#import "PreferencesController.h"

#define kBundleIdentifierFireFox @"org.mozilla.firefox"
#define kBundleIdentifierSafari @"com.apple.Safari"


@interface ApplicationController (Private)
- (BOOL)_copyPlugIn:(FlashPlugInVO *)plugIn toDirectory:(NSString *)path error:(NSError **)error;
- (BOOL)_copyFileAtPath:(NSString *)sourcePath toPath:(NSString *)targetPath error:(NSError **)error;
- (void)_setPlugInIsSwitching:(BOOL)value;
- (void)_invalidateSwitchButton;
@end


@implementation ApplicationController

#pragma mark -
#pragma mark Initialization & Deallocation

+ (void)initialize
{
	// register default values for standardUserDefaults
	NSMutableDictionary *appDefaults = [NSMutableDictionary dictionary];
	[appDefaults setObject:[NSNumber numberWithBool:YES] forKey:KEY_CHECK_FOR_UPDATES];
	[appDefaults setObject:[NSNumber numberWithBool:YES] forKey:KEY_RESTART_SAFARI];
	[appDefaults setObject:[NSNumber numberWithBool:YES] forKey:KEY_RESTART_FIREFOX];
    [[NSUserDefaults standardUserDefaults] registerDefaults:appDefaults];
}

- (id)init
{
	if (self = [super init])
	{
		NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, 
			NSUserDomainMask, YES);
		appSupportFolder = [[[paths objectAtIndex:0] 
			stringByAppendingPathComponent:@"WSPluginSwitcher"] retain];
		prefController = nil;
		plugInSwitcher = nil;
	}
	return self;
}

- (void)awakeFromNib
{
	[archiveFlashPluginsFoldersController addObserver:self forKeyPath:@"arrangedObjects" options:0 
		context:NULL];
	[appModel updateArchiveFlashPluginFolders];
	// show preference panel if an user haven't stored archive folders
	NSString *archiveFlashPluginsFolders = [[NSUserDefaults standardUserDefaults] 
		stringForKey:KEY_ARCHIVE_FLASH_PLUGINS_FOLDERS];
		
	if (!archiveFlashPluginsFolders)
	{	
		[b_switchFlashPlugin setEnabled:NO];
		[self showPreferencePanel:nil];
	}
}

- (void)dealloc
{
	[prefController release];
	[appSupportFolder release];
	[plugInSwitcher release];
	[super dealloc];
}



#pragma mark -
#pragma mark IB methods

- (IBAction)showPreferencePanel:(id)sender
{
	if (!prefController)
	{
		prefController = [[PreferencesController alloc] init];
		[prefController setAppModel:appModel];
	}
	[prefController showWindow:self];		
}

- (IBAction)switchFlashPluginHandler:(id)sender
{
	// get selected plugin
	FlashPlugInVO *plugInVO = (FlashPlugInVO *)[[archiveFlashPluginsFoldersController 
		selectedObjects] objectAtIndex:0];
	
	// nothing to do, plugins are equal
	if ([[plugInVO versionString] isEqualToString:appModel.installedPlugIn.versionString])
	{
		return;
	}

	[self _setPlugInIsSwitching:YES];
	
	// switcher, which spins off the worker process (with root privileges if needed)
	plugInSwitcher = [[PlugInSwitcher alloc] init];
	plugInSwitcher.delegate = self;
	
	// backup currently installed flash player if it is not present in the archive
	if (appModel.installedPlugIn && ![appModel containsPlugIn:appModel.installedPlugIn])
	{
		NSString *backupPath = [[[NSUserDefaults standardUserDefaults] 
			stringForKey:KEY_ARCHIVE_FLASH_PLUGINS_FOLDERS] 
			stringByAppendingPathComponent:plugInVO.versionString];
		NSFileManager *fm = [NSFileManager defaultManager];
		NSError *error = nil;
		
		if (![fm fileExistsAtPath:backupPath])
		{
			if (![fm createDirectoryAtPath:backupPath withIntermediateDirectories:YES attributes:nil 
				error:&error])
			{
				[NSApp presentError:error];
				return;
			}
		}
		[plugInSwitcher addPlugInToQueue:appModel.installedPlugIn withTargetDirectory:backupPath];
	}
	// now install selected plugin
	[plugInSwitcher addPlugInToQueue:plugInVO withTargetDirectory:DEFAULT_PLUGINS_FOLDER];
	// fire (after next runloop). this brings up a potential password dialog after our button 
	// was released, which would be kind of a visual glitch
	[plugInSwitcher performSelector:@selector(beginSwitching) withObject:nil afterDelay:0.0];
}



#pragma mark -
#pragma mark Observer methods

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
	change:(NSDictionary *)change context:(void *)context
{
	if (object == archiveFlashPluginsFoldersController)
	{
		[self _invalidateSwitchButton];
	}
}



#pragma mark -
#pragma mark Private methods

- (void)_setPlugInIsSwitching:(BOOL)value
{
	// behavior of loader image
	if (value)
	{
		[loader startAnimation:nil];
	}
	else
	{
		[loader stopAnimation:nil];
	}
	[b_switchFlashPlugin setEnabled:!value];
}

- (void)_restartBrowsersThreaded:(NSArray *)browserNames
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	NSURL *aURL = [NSURL URLWithString:@"http://www.playerversion.com"];
	for (NSString *name in browserNames)
	{
		NSArray *launchedApplications = [[NSWorkspace sharedWorkspace] 
			valueForKeyPath:@"launchedApplications.NSApplicationName"];
		NSString *actionDescription = @"start";
		NSMutableString *scriptTxt = [NSMutableString stringWithFormat:@"tell application \"%@\"\n", name];
		if ([launchedApplications containsObject:name])
		{
			[scriptTxt appendString:@"quit\ndelay 2\n"];
			actionDescription = @"restart";
		}
		[scriptTxt appendFormat:@"activate\nopen location \"%@\"\nend tell", [aURL absoluteString]];
		NSAppleScript *script = [[NSAppleScript alloc] initWithSource:scriptTxt];
		NSAppleEventDescriptor *result = [script executeAndReturnError:nil];
		if (result == nil)
		{
			[self performSelectorOnMainThread:@selector(_restartBrowsersThreadedDidFail) 
				withObject:nil waitUntilDone:NO];
		}
		[script release];
	}
	[self performSelectorOnMainThread:@selector(_restartBrowsersThreadedDidComplete) 
		withObject:nil waitUntilDone:NO];
	
	[pool drain];
	[pool release];
}

- (void)_restartBrowsersThreadedDidComplete
{
	[self _setPlugInIsSwitching:NO];
}

- (void)_restartBrowsersThreadedDidFail
{
	[NSApp presentError:[NSError errorWithDomain:kWSPluginSwitcherErrorDomain code:-1 
		title:@"Could not restart your browsers!" 
		description:@"There was an unexpected AppleScript error"]];
	[self _setPlugInIsSwitching:NO];
}

- (void)_invalidateSwitchButton
{
	[b_switchFlashPlugin setEnabled:plugInSwitcher == nil && 
		[[archiveFlashPluginsFoldersController arrangedObjects] count] > 0];
}



#pragma mark -
#pragma mark PlugInSwitcherDelegate methods

- (void)plugInSwitcher:(PlugInSwitcher *)switcher didSwitchPlugIn:(FlashPlugInVO *)plugIn
{
	// backup complete
	if (plugIn == appModel.installedPlugIn)
	{
		[appModel addPlugIn:appModel.installedPlugIn];
	}
	// install complete
	else
	{
		appModel.installedPlugIn = plugIn;
	}
}

- (void)plugInSwitcherDidSwitchPlugIns:(PlugInSwitcher *)switcher
{
	NSMutableArray *browsersToRestart = [NSMutableArray array];
	// restart browsers if needed
	if ([[NSUserDefaults standardUserDefaults] boolForKey:KEY_RESTART_FIREFOX])
	{
		[browsersToRestart addObject:@"Firefox"];
	}
	if ([[NSUserDefaults standardUserDefaults] boolForKey:KEY_RESTART_SAFARI])
	{
		[browsersToRestart addObject:@"Safari"];
	}
	[plugInSwitcher release];
	plugInSwitcher = nil;
	
	if ([browsersToRestart count] > 0)
	{
		[NSThread detachNewThreadSelector:@selector(_restartBrowsersThreaded:) toTarget:self 
			withObject:browsersToRestart];
		return;
	}
	[self _setPlugInIsSwitching:NO];
}

- (void)plugInSwitcher:(PlugInSwitcher *)switcher didFailWithError:(NSError *)error
{
	[NSApp presentError:error];
	[plugInSwitcher release];
	plugInSwitcher = nil;
	[self _setPlugInIsSwitching:NO];
}



#pragma mark -
#pragma mark NSApplicationDelegate methods

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
	if (plugInSwitcher != nil)
	{
		return NSTerminateCancel;
	}
	return NSTerminateNow;
}

@end